from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import paho.mqtt.client as mqtt
import cv2
import logging
import numpy as np
import hashlib
import json


class Message(object):
    def reg(user_name,  password):
        if(len(user_name) > 8):
            raise 'password error'
        pwd = hashlib.md5(password.encode('ascii')).hexdigest()
        channel = "/" + str(user_name) + pwd[0]
        data = {
            'version': '1.0',
            'method': 'REG',
            'username': str(user_name),
            'password': pwd
        }
        return json.dumps(data), channel

    def login(userid,  password):
        pwd = hashlib.md5(password.encode('ascii')).hexdigest()
        channel = "/" + str(userid) + pwd[0]
        data = {
            'version': '1.0',
            'method': 'LOGIN',
            'userid': str(userid),
            'password': pwd
        }
        return json.dumps(data), channel

    def ping(userid,  session):
        data = {
            'version': '1.0',
            'method': 'PING',
            'userid': str(userid),
            'session': session
        }
        return json.dumps(data)

    def userlist(userid,  session):
        data = {
            'version': '1.0',
            'method': 'USERLIST',
            'userid': str(userid),
            'session': session
        }
        return json.dumps(data)

    def addfriend(userid,  session,  userid_add):
        data = {
            'version': '1.0',
            'method': 'ADDFRIEND',
            'session': session,
            'userid': str(userid),
            'request': str(userid_add)
        }
        return json.dumps(data)

    def delfriend(userid,  session,  userid_del):
        data = {
            'version': '1.0',
            'method': 'DELFRIEND',
            'session': session,
            'userid': str(userid),
            'request': str(userid_del)
        }
        return json.dumps(data)

    def listfriend(userid,  session):
        data = {
            'version': '1.0',
            'method': 'LISTFRIEND',
            'userid': str(userid),
            'session': session,
        }
        return json.dumps(data)

    def chat_req(userid,  session,  request):
        data = {
            'version': '1.0',
            'method': 'CHAT',
            'userid': str(userid),
            'request': request,
            'session': session,
        }
        return json.dumps(data)

    def message(user_id, session, message):
        data = {
            'type': 'TEXT',
            'user_id': user_id,
            'session': session,
            'message': message
        }
        return json.dumps(data)


class MainMQTT(mqtt.Client):
    def __init__(self):
        super().__init__()
        self.login_ack = None
        self.login_rej = None
        self.onlinelist_update = None
        self.friendlist_update = None
        self.chat_ack = None
        self.chat_rej = None
        self.addf_ack = None
        self.addf_rej = None
        self.addfriend_to = None
        self.register_ack = None
        self.register_rej = None
        self.message_rec = None
        self.usermessage_rec = None

    def connect_server(self, addr="127.0.0.1", port=1883):
        res = self.connect(
            addr, port=port, keepalive=60, bind_address="")
        self.loop_start()
        return res

    def send_message(self, user_id, session, message):
        payload = Message.message(self.user_id, self.session, message)
        self.publish("/" + user_id + "/" + session, payload=payload, qos=2)
        logging.info("send_message:")
        logging.debug(payload)

    def register(self, user_name, user_pwd):
        payload, self.ctrl_channel = Message.reg(user_name, user_pwd)
        self.subscribe("/listener" + self.ctrl_channel, 2)
        self.publish("/manage", payload=payload, qos=2)
        logging.info("register:")
        logging.debug(payload)

    def login(self, user_id, user_pwd):
        self.user_id = user_id
        payload, self.ctrl_channel = Message.login(self.user_id, user_pwd)
        self.subscribe("/listener" + self.ctrl_channel, 2)
        self.publish("/manage", payload=payload, qos=2)
        logging.info("login:")
        logging.debug(payload)

    def getuserlist(self):
        payload = Message.userlist(self.user_id, self.session)
        self.publish("/manage", payload=payload, qos=2)
        logging.info("getuserlist:")
        logging.debug(payload)

    def getfriendlist(self):
        payload = Message.listfriend(self.user_id, self.session)
        self.publish("/manage", payload=payload, qos=2)
        logging.info("getfriendlist:")
        logging.debug(payload)

    def ping(self):
        payload = Message.ping(self.user_id, self.session)
        self.publish("/manage", payload=payload, qos=2)
        logging.info("ping:")
        logging.debug(payload)

    def chat(self, user_id):
        payload = Message.chat_req(self.user_id, self.session, [user_id])
        self.publish("/manage", payload=payload, qos=2)
        logging.info("chat_req:")
        logging.debug(payload)

    def addfriend(self, user_id):
        payload = Message.addfriend(self.user_id, self.session, user_id)
        self.publish("/manage", payload=payload, qos=2)
        logging.info("addf_req:")
        logging.debug(payload)

    def sendmessage(self, payload, user_id, user_session, qos=2):
        topic = "/" + user_id + "/" + user_session
        self.publish(topic, payload=payload, qos=qos)
        logging.info("sendmessage:")
        logging.debug(topic)
        logging.debug(payload)

    def on_connect(self, client, userdata, flags, rc):
        topic = ["/listener"]
        for t in topic:
            client.subscribe(t, 2)

    def on_message(self, client, userdata, message):
        logging.info("on_message:")
        logging.debug(message.topic)
        logging.debug(message.payload)
        topic_tree = message.topic.split("/")
        try:
            string = str(bytes(message.payload), "utf-8")
            isstring=True
        except:
            isstring=False
        if isstring and string[0] == "{" and string[-1] == "}":
            data = json.loads(string)
            if data['type'] == 'REG':
                if data['error'] == '0':
                    self.register_ack(data["userid"])
                else:
                    self.register_rej()
            elif data['type'] == 'LOGIN':
                if data['error'] == '0':
                    self.session = data['session']
                    self.user_topic_root = "/" + self.user_id + "/" + self.session
                    self.subscribe("/listener" + self.user_topic_root)
                    self.subscribe(self.user_topic_root + "/#", 1)
                    logging.debug("listening:")
                    logging.debug(self.user_topic_root)
                    self.login_ack(self.user_id, self.session)
                else:
                    self.login_rej()
            elif data['type'] == 'PING':
                if data['error'] == '0':
                    self.onlinelist_update(data['userlist'])
            elif data['type'] == 'USERLIST':
                if data['error'] == '0':
                    self.onlinelist_update(data['userlist'])
            elif data['type'] == 'LISTFRIEND':
                if data['error'] == '0':
                    self.friendlist_update(data['friendlist'])
            elif data['type'] == 'CHAT':
                if data['error'] == '0':
                    self.chat_ack(data['online'])
                else:
                    self.chat_rej()
            elif data['type'] == 'ADDFRIEND':
                if data['error'] == '0':
                    self.addf_ack()
                else:
                    self.addf_rej()
            elif data['type'] == 'ADDFRIEND_TO':
                if data['error'] == '0':
                    self.addfriend_to(data['request_user'])
            elif data['type'] == 'TEXT':
                try:
                    self.message_rec(data)
                except:
                    pass
            else:
                logging.debug("user message reveiced")
                self.usermessage_rec(message)
        else:
            logging.debug("user message reveiced")
            self.usermessage_rec(message)
